package arithmetic.thread;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author jiangfeng on 2022/1/24
 */
public class TestTreadPool {

    public static void main(String[] args) {
        TreadPool treadPool = new TreadPool(3);

        //ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i=0;i<10;i++) {
            int finalI = i;
            treadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"  "+ finalI);
            });
        }

        System.out.println("搞定收工");
    }

    static class TreadPool implements Executor {

        final int coreSize;
        final AtomicInteger doneSize = new AtomicInteger(0);

        final Worker[] workers;

        TreadPool(int coreSize) {
            this.coreSize = coreSize;

            // 初始化worker
            workers = new Worker[coreSize];
            for (int i = 0; i < coreSize; i++) {
                workers[i] = new Worker();
                new Thread(workers[i]).start();
            }

            // 启动一个后台线程看是否有任务要执行
            new Thread(() -> {
                Runnable runnable = null;
                try {
                    runnable = tasks.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                while (runnable != null) {
                    Worker freeWorker;
                    while ((freeWorker = getFreeWorker()) == null) {
                    }

                    freeWorker.runTask(runnable);
                    //  没拿到任务就阻塞,循环取新任务
                    try {
                        runnable= tasks.take();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        final LinkedBlockingQueue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();



        private Worker getFreeWorker() {
            //一直循环看所有worker变量是否变更
            for (Worker worker : workers) {
                // 没取到就换下个?
                if (worker.isWokering.compareAndSet(false, true)) {
                    return worker;
                }
            }
            return null;
        }

        //ExecutorService executorService = Executors.newSingleThreadExecutor();
        @Override
        public void execute(Runnable command) {
            // 1. 获取工作线程
            Worker worker = getFreeWorker();
            if(worker==null){
                // 后台线程执行
                tasks.add(command);
                return;
            }

            // 执行任务,
            worker.runTask(command);
            int i = doneSize.incrementAndGet();
            System.out.println("完成任务数:"+i);
        }


        class Worker implements Runnable {

            //0 执行任务中,1执行完成
            final AtomicBoolean isWokering;
           // final SynchronousQueue<Runnable> tasks;

            Worker() {
                isWokering = new AtomicBoolean(false);
                //tasks = new SynchronousQueue<Runnable>();
            }

            public void runTask(Runnable task) {
                try {
                    tasks.put(task);
                } catch (InterruptedException e) {
                    System.out.println("线程放入任务 阻塞了");
                    e.printStackTrace();
                }
                //isWokering.set(false);
            }

            @Override
            public void run() {
                try {
                    Runnable take = tasks.take();
                    while (take != null) {
                        take.run();
                        isWokering.set(false);
                        take = tasks.take();
                    }


                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }



}
